package com.jlect.swebing.ui.laf.basic.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
import com.jlect.swebing.ui.client.*;
import com.jlect.swebing.ui.client.laf.ComponentUI;
import com.jlect.swebing.util.client.Strings;

/**
 * Base implementation of the common methods for GWT UI library.
 *
 * @author Sergey Kozmin
 * @since 06.12.2007 9:56:32
 */
public abstract class AbstractComponentUI implements ComponentUI, WidgetProvider, AttachListener, PropertyChangeListener, ComponentListener {
    private Widget widget;
    private boolean wasInitialized;
    private EligibilityListener eligibilityListener;
    private GComponent component;

    public void installUI(GComponent c) {
        if(c == null) {
            throw new IllegalArgumentException("Could not work with null object component. ");
        }
        component = c;
        c.addPropertyListener(this);
        c.addComponentListener(this);
    }

    public void uninstallUI(GComponent c) {
        component = null;
    }

    protected GComponent getComponent() {
        return component;
    }

    public void setEligibilityListener(EligibilityListener listener) {
        this.eligibilityListener = listener;
    }

    /*public boolean isEligibile() {
        return getWidget().isAttached();
    }
*/
    public Widget getWidget() {
        if(!wasInitialized) {
            wasInitialized = true;
            if((widget = provideWidget()) == null) {
                throw new IllegalStateException("AbstractGWTRenderer wasn't initialized with widget. Class [" +
                        GWT.getTypeName(this) + "]. ");
            }
            if(widget instanceof AttachEventSource) {
                ((AttachEventSource)widget).setAttachListener(this);
            } else {
                throw new IllegalArgumentException("Widget must implement AttachEventSource interface, so it correctly" +
                        " behaive as a renderer. Income widget class [" + GWT.getTypeName(widget) + "]. ");
            }
        }
        return widget;
    }

    /**
     * This method provides widget of the specific implementation and implements Factory Method pattern.
     * It will be called once per object life.
     * @return widget of this provider
     */
    protected abstract Widget provideWidget();

    protected void setWidget(Widget widget) {
        this.widget = widget;
    }

    public void onLoad() {
        ComponentsRegister.getRegister().registerComponent(widget.getElement(), this);
        if(eligibilityListener != null) {
            eligibilityListener.componentEligible(component);
        }
    }

    public void onUnload() {
        if(eligibilityListener != null) {
            eligibilityListener.componentNotEligible(component);
        }
        ComponentsRegister.getRegister().registerComponent(widget.getElement(), this);
    }

    public void propertyChange(PropertyChangeEvent evt) {
        if(GComponent.DISABLED_PROPERTY_NAME.equalsIgnoreCase(evt.getPropertyName())) {//todo optimize
            setEnabled((Boolean)evt.getNewValue());
        }
    }

    public void componentResized(ComponentEvent e) {
        Dimension dimension = component.getSize();
        setSize(dimension.width, dimension.height);
    }

    public void componentMoved(ComponentEvent e) {
        Location location = component.getLocation();
        setLocation(location.getX(), location.getY());
    }

    public void componentShown(ComponentEvent e) {
        //dont react on it
    }

    public void componentHidden(ComponentEvent e) {
        //dont react on it
    }

    public void setWidth(int width) {
        getWidget().setWidth(Strings.toPixelString(width));//todo implement resize-on-attach algorithm
    }

    public void setHeight(int height) {
        getWidget().setHeight(Strings.toPixelString(height));//todo implement resize-on-attach algorithm
    }

    public void setBounds(int x, int y, int width, int height) {
        setLocation(x, y);
        setSize(width, height);
    }

    public void setLocation(int x, int y) {
        Element elem = getWidget().getElement();
        DOM.setStyleAttribute(elem, "position", "absolute");
        DOM.setStyleAttribute(elem, "left", x + "px");
        DOM.setStyleAttribute(elem, "top", y + "px");
    }

    public void setSize(int width, int height) {
        Widget widget = getWidget();
        widget.setWidth(Strings.toPixelString(Math.max(width, 0)));
        widget.setHeight(Strings.toPixelString(Math.max(height, 0)));
    }

    protected void setEnabled(boolean enabled) {
    }

/*    public int getWidth() {
        Widget theWidget = getWidget();
        return theWidget.isAttached() ? theWidget.getOffsetWidth() : 0;//todo make it returns stored value, that will be set after widget attached
    }

    public int getHeight() {
        Widget theWidget = getWidget();
        return theWidget.isAttached() ? theWidget.getOffsetHeight() : 0;//todo make it returns stored value, that will be set after widget attached
    }

    public int getX() {
        Widget theWidget = getWidget();
        return theWidget.isAttached() ? Strings.pixelToString(DOM.getStyleAttribute(theWidget.getElement(), "left")) : 0;//todo make it returns stored value, that will be set after widget attached
    }

    public int getY() {
        Widget theWidget = getWidget();
        return theWidget.isAttached() ? Strings.pixelToString(DOM.getStyleAttribute(theWidget.getElement(), "top")) : 0;//todo make it returns stored value, that will be set after widget attached
    }*/
}
